package my.mark.mybaibaoxiang.threadPoolCheck;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author wxming.
 * @Description TODO.线程池服务，初始化自己的复用线程池。
 * 该类中初始化各业务线的一个线程，每个业务线只有一个线程且一直存活，即需要检查存活状态的线程。
 以及业务线程里又需要嵌套的各个线程池。即初始化自己的复用线程池。
 * 各业务的线程中while(true){Thread.sleep()}一直跑着业务循环。根据业务情况，可以只有这一个循环去刷业务。
 * 也可以在循环中获取到批量数据都去使用各自对应的线程池，再发起线程。
 *
 *
 * 实现org.springframework.beans.factory.DisposableBean接口的bean允许在容器销毁该bean的时候获得一次回调。DisposableBean接口也只规定了一个方法：
void destroy() throws Exception;
 *
 * 提供各线程从上下文获取对象实例的工具。
 * @date 2020-6-8.
 */
@Component("oneThreadPoolService")
public class OneThreadPoolService implements ApplicationContextAware,ApplicationListener<ContextRefreshedEvent>,DisposableBean{
    private static final Logger logger = LoggerFactory.getLogger(OneThreadPoolService.class);
    private static ApplicationContext applicationContext;

    private ThreadPoolExecutor sendThreadPoolExecutor = null;
    private ThreadPoolExecutor firstThreadPoolExecutor = null;

    private Thread oneThread = null;
    private Thread sendThread = null;

    //线程数
    int cPoolSize = 7;
    int sPoolSize = 7;

    @Override
    public void destroy() throws Exception {
        logger.info("destroy threadPoolService");
        if(null != oneThread){
            /**
             * interrupt() 方法只是改变中断状态而已，它不会中断一个正在运行的线程。
             这一方法实际完成的是，给受阻塞的线程发出一个中断信号，这样受阻线程就得以退出阻塞的状态。
             */
            oneThread.interrupt();
        }
        if(null != sendThread){
            sendThread.interrupt();
        }
        if(firstThreadPoolExecutor != null){
            firstThreadPoolExecutor.shutdown();
        }
        if(sendThreadPoolExecutor != null){
            sendThreadPoolExecutor.shutdown();
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        OneThreadPoolService.applicationContext = applicationContext;
    }

    public static Object getBean(String name){
        return applicationContext.getBean(name);
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        if(contextRefreshedEvent.getApplicationContext().getParent() == null){
            try{
                logger.info("线程池服务开始初始化");
                //从上下文获取个对象
                OneUtil oneUtil = (OneUtil)contextRefreshedEvent.getApplicationContext().getBean("oneUtil");

                logger.info("线程池服务开始初始化");
                firstThreadPoolExecutor = new ThreadPoolExecutor(cPoolSize,cPoolSize,0L, TimeUnit.MINUTES,new LinkedBlockingDeque<Runnable>()){
                    @Override
                    protected void afterExecute(Runnable r, Throwable t) {
                        super.afterExecute(r,t);
                        if(t != null){
                            System.out.println("first thread pools execute error" + t);
                        }else{
                            System.out.println("first thread pools execute sucecess");
                        }
                    }
                };
                firstThreadPoolExecutor = new ThreadPoolExecutor(sPoolSize,sPoolSize,0L, TimeUnit.MINUTES,new LinkedBlockingDeque<Runnable>());
                logger.info("线程池服务初始化成功");

                sendThread = new Thread(new SendThread());
                sendThread.start();
                logger.info("定时初审线程开始执行");

                //罗列启动各业务线程
                /*oneThread = new Thread(new SendThread());
                oneThread.start();
                logger.info("定时初审线程开始执行");*/

            }catch (Exception e){
                logger.error("线程池初始化异常",e);
                System.exit(1);//TODO 启动初始异常便退出程序
            }
        }
    }

    //罗列各业务线程调用各自的线程池（方法参数实际传入各自的业务传值对象）
    public void execProcess(Object o) throws Exception{
        ExecSendThread execSendThread = new ExecSendThread(o);
        sendThreadPoolExecutor.execute(execSendThread);
    }

    //罗列各线程的判断线程是否活着
    public boolean iSSendAlive() {
        if(null != sendThread){
            return sendThread.isAlive();
        }
        return false;
    }

    //罗列设置各业务当前线程
    public void setSendThread(Thread sendThread) {
        this.sendThread = sendThread;
    }

}

//一个业务线程
class SendThread implements Runnable{

    private OneThreadPoolService oneThreadPoolService;

    @Override
    public void run() {
        //从上下文获取个对象
        oneThreadPoolService= (OneThreadPoolService)OneThreadPoolService.getBean("oneThreadPoolService");
        long sleepTime=2;
        while (true){
            try{
                System.out.println("业务线程一直跑");

                //业务线程中再发起自己的子线程，使用自己的线程池。
                oneThreadPoolService.execProcess(new Object());

                Thread.sleep(sleepTime*1000);
            }catch (Exception e){
                e.printStackTrace();
                try {
                    Thread.sleep(sleepTime*1000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
}

//一个业务执行的子线程。
class ExecSendThread implements Runnable{

    Object oo;
    public ExecSendThread(Object o){
        oo = o;
    }

    @Override
    public void run() {
        //从上下文获取个对象
        OneUtil oneUtil = (OneUtil)OneThreadPoolService.getBean("oneUtil");
        System.out.println("to run"+oo.toString());
    }
}
